﻿using System;
using System.Security.Cryptography;
using System.Text;

namespace Odyssey.BouncyCastle.RSAUtil.Implementations
{
    public class RSADispatch : IRSADispatch
    {
        private RSA _privateRSA;
        private RSA _publicRSA;
        private Encoding _dataEncoding;

        public RSADispatch(RSA privateRSA, RSA publicRSA, Encoding dataEncoding)
        {
            _privateRSA = privateRSA;
            _publicRSA = publicRSA;
            _dataEncoding = dataEncoding;
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public string Decrypt(string data, RSAEncryptionPadding padding)
        {
            if (_privateRSA == null)
            {
                throw new ArgumentException("RSA decrypt faild! private key can not null");
            }
            var dataBytes = _dataEncoding.GetBytes(data);
            var decryptBytes = _privateRSA.Decrypt(dataBytes, padding);
            return _dataEncoding.GetString(decryptBytes);
        }

        public void Dispose()
        {
            _privateRSA?.Dispose();
            _publicRSA?.Dispose();
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public string Encrypt(string data, RSAEncryptionPadding padding)
        {
            if (_publicRSA == null)
            {
                throw new ArgumentException("RSA encrypt faild! public key can not null");
            }
            var dataBytes = _dataEncoding.GetBytes(data);
            var decryptBytes = _privateRSA.Encrypt(dataBytes, padding);
            return Convert.ToBase64String(decryptBytes);
        }

        /// <summary>
        /// 签名
        /// </summary>
        /// <param name="data"></param>
        /// <param name="hashAlgorithmName"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public string Sign(string data, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)
        {
            var signBytes = SignBytes(data, hashAlgorithmName, padding);
            return Convert.ToBase64String(signBytes);
        }

        public byte[] SignBytes(string data, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)
        {
            if (_privateRSA == null)
            {
                throw new ArgumentException("RSA sign faild! private key can not null");
            }
            var dataBytes = _dataEncoding.GetBytes(data);
            return _privateRSA.SignData(dataBytes, hashAlgorithmName, padding);
        }

        /// <summary>
        /// 验签
        /// </summary>
        /// <param name="data"></param>
        /// <param name="sign"></param>
        /// <param name="hashAlgorithmName"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public bool VerifySign(string data, string sign, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)
        {
            if (_publicRSA == null)
            {
                throw new ArgumentException("RSA verify sign faild! public key can not null");
            }

            var dataBytes = _dataEncoding.GetBytes(data);
            var signBytes = Convert.FromBase64String(sign);
            return _publicRSA.VerifyData(dataBytes, signBytes, hashAlgorithmName, padding);
        }
    }
}
